﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sherwood.Security;

namespace Sherwood.SignOn.Server.Models.Repositories.Sql
{
    public partial class UserAccount : IUserAccount
    {

        public string CreateVerificationCode()
        {
            //Change
            VerificationCode = Guid.NewGuid().ToString();

            //Persist
            SqlRepositoryDataContext db = new SqlRepositoryDataContext();
            var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
            if (account != null)
            {
                account.VerificationCode = VerificationCode;
            }
            db.SubmitChanges();
            db.Dispose();

            //Return
            return VerificationCode;
        }

        public bool ValidateVerificationCode(string verificationCode)
        {
            return verificationCode != null && VerificationCode != null && VerificationCode.Equals(verificationCode.Trim());
        }

        public bool ValidateProposedEmailAndPasswordChange(string verificationCode)
        {
            if (ValidateVerificationCode(verificationCode))
            {
                SqlRepositoryDataContext db = new SqlRepositoryDataContext();
                if (!string.IsNullOrEmpty(ProposedEmail))
                {
                    string email = ProposedEmail.ToLower();

                    IUserAccount existingUser = (from u in db.UserAccounts where u.Email != null && u.Email.ToLower() == email select u).FirstOrDefault();
                    if (existingUser != null && !existingUser.Id.Equals(Id))
                    {
                        return false; //another user has the proposed email address! This could for example happen if the user decides to create a new account after trying to change an existing account.
                    }
                    Email = ProposedEmail;
                    ProposedEmail = "";
                }
                if (!string.IsNullOrEmpty(ProposedPasswordHash))
                {
                    PasswordHash = ProposedPasswordHash;
                    ProposedPasswordHash = "";
                }
                VerificationCode = "";

                //Persist
                var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
                if (account != null)
                {
                    account.VerificationCode = VerificationCode;
                    account.Email = Email;
                    account.ProposedEmail = null;
                    account.PasswordHash = PasswordHash;
                    account.ProposedPasswordHash = ProposedPasswordHash;
                }
                db.SubmitChanges();
                db.Dispose();

                return true;
            }
            return false;
        }

        public void SetVerificationParameters(VerificationStatus verificationStatus, string requestedUrl, string verificationCode)
        {

            VerificationCode = verificationCode;
            VerificationStatus = verificationStatus;
            RequestedUrl = requestedUrl;

            //Persist
            SqlRepositoryDataContext db = new SqlRepositoryDataContext();
            var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
            if (account != null)
            {
                account.VerificationCode = VerificationCode;
                account.VerificationStatus = VerificationStatus;
                account.RequestedUrl = RequestedUrl;
            }
            db.SubmitChanges();
            db.Dispose();
        }

        public bool SetPassword(string password)
        {
            try
            {
                //Change
                string algorithm = "SHA256";
                string hash = Hash.ComputeHash(password, algorithm, null);
                PasswordHash = algorithm + ":" + hash;

                //Persist
                SqlRepositoryDataContext db = new SqlRepositoryDataContext();
                var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
                if (account != null)
                {
                    account.PasswordHash = PasswordHash;
                }
                db.SubmitChanges();
                db.Dispose();

                return true;
            }
            catch
            {
                return false;
            }
        }

        public string SetProposedEmailAndPassword(string email, string password)
        {
            if (!string.IsNullOrEmpty(password))
            {
                try
                {
                    string algorithm = "SHA256";
                    string hash = Hash.ComputeHash(password, algorithm, null);
                    ProposedPasswordHash = algorithm + ":" + hash;
                }
                catch
                {
                    return null;
                }
            }
            ProposedEmail = email;
            string verificationCode = CreateVerificationCode();
            if (VerificationStatus == Sherwood.SignOn.VerificationStatus.Verified || VerificationStatus == Sherwood.SignOn.VerificationStatus.ResetPassword)
            {
                if (!Email.Equals(ProposedEmail) || !string.IsNullOrEmpty(password))
                {
                    VerificationStatus = Sherwood.SignOn.VerificationStatus.ResetPassword;
                }
                else
                {
                    VerificationStatus = Sherwood.SignOn.VerificationStatus.Verified;
                }
            }

            //Persist
            SqlRepositoryDataContext db = new SqlRepositoryDataContext();
            var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
            if (account != null)
            {
                account.ProposedPasswordHash = ProposedPasswordHash;
                account.ProposedEmail = ProposedEmail;
                account.VerificationStatus = VerificationStatus;
            }
            db.SubmitChanges();
            db.Dispose();

            return verificationCode;
        }

        public bool VerifyPassword(string password)
        {
            if (!string.IsNullOrEmpty(PasswordHash))
            {
                string[] parts = PasswordHash.Split(':');
                string algorithm = parts[0];
                string hash = "";
                if (parts.Length > 0)
                {
                    for (int i = 1; i < parts.Length; i++)
                    {
                        hash = hash + ":" + parts[i];
                    }
                }
                hash = hash.TrimStart(':');
                if (hash.Length > 0)
                {
                    try
                    {
                        return Hash.VerifyHash(password, algorithm, hash);
                    }
                    catch
                    {
                        return false;
                    }
                }
            }
            return false;
        }

        public string DisplayName
        {
            get
            {
                string firstName = FirstName != null ? FirstName : "";
                string lastName = LastName != null ? LastName : "";
                return (firstName + " " + lastName).Trim();
            }
        }



        public void SetEnabled(bool enabled)
        {
            //Change
            IsEnabled = enabled;

            //Persist
            SqlRepositoryDataContext db = new SqlRepositoryDataContext();
            var account = (from u in db.UserAccounts where u.Id.Equals(Id) select u).FirstOrDefault();
            if (account != null)
            {
                account.IsEnabled = enabled;
            }
            db.SubmitChanges();
            db.Dispose();
        }


    }

}
